﻿#include <arch/arm64/Arm64.h>
#include <arch/arm64/System.h>
#include <arch/arm64/Special.h>

#define TAG "ARM64_OPCODE"

Arm64OpDecorder::Arm64OpDecorder()
{
	_core = new struct GeneralRegisiter();
	_special = new struct SpecialRegisiter();
	_system = new struct SystemRegisiter();
	_pc = 0;
	_pstate = new struct PSTATE();
	_tstate = new struct TSTATE();
};

Arm64OpDecorder::~Arm64OpDecorder()
{
	if (_core != nullptr) {
		delete _core;
		_core = nullptr;
	}
	if (_special != nullptr) {
		delete _special;
		_special = nullptr;
	}
	if (_system != nullptr) {
		delete _system;
		_system = nullptr;
	}
	if (_pstate != nullptr) {
		delete _pstate;
		_pstate = nullptr;
	}
	if (_tstate != nullptr) {
		delete _tstate;
		_tstate = nullptr;
	}
}


int Arm64OpDecorder::decoder(uint32_t code)
{
	int op1 = GetBitMap(code,25,3);// ((code >> 25) & 0x0F);

	int ret = 0;
	LogZ("decoder pc cmd->" << std::hex <<"pc:0x" << _pc << ",cmd:0x" << code);
	// 取下一指令
	//_pc += 4;
	switch (op1)
	{
	case 4:
	case 6:
	case 12:
	case 14:
		LogZ("GROUP:Loads and Stores");
		ret = _loadAndStores(code);
		break;
	case 7:
	case 15:
		Abort("get pc code:" << std::hex << code << ":" << op1);
		break;
	case 5:
	case 13:
		Abort("get pc code:" << std::hex << code << ":" << op1);
		break;
	case 10:
	case 11:
		LogZ("GROUP:Branches, Exception Generating and System instructions");
		ret = _generalSys(code);
		break;
	case 8:
	case 9:
		LogZ("GROUP:Data Processing -- Immediate");
		ret = _dataProcessing(code);
		break;
	case 2:
		Abort("get pc code:" << std::hex << code << ":" << op1);
		break;
	case 0: 
	{
		Abort("get pc code:" << std::hex << code << ":" << op1);
		bool op0 = GetBitBool(code, 31);// code & 0x80000000;
		if (op0)
		{
			ret = _smeEncodings(code);
		}
		else {
			ret = _reserved(code);
		}
	}
		break;
	case 1:
	case 3:
	default:
		goto noCode;
	}
	LogZ("**************************************");
	if(ret == 0)
		return 0;
noCode:
	Abort("get err pc code:" << std::hex << code << ":" << op1 << ":" << ret);
}

uint64_t Arm64OpDecorder::getPC()
{
	return _pc;
}

inline void Arm64OpDecorder::_pcNext()
{
	_pc += 4;
}

// Reserved 组
// op1 = 0000 op0 = 0
int Arm64OpDecorder::_reserved(uint32_t code)
{
	bool op0 =  code & 0x60000000;
	bool op1 =  code & 0x01ff0000;
	if (!op0 && !op1) {
		//UDE:永久未定义会生成未定义指令异常 （ESR_ELx.EC = 0b000000）。的编码本节中使用的 UDF 定义为永久未定义。
		//调试中使用,导致一个未定义异常,低16位是一个立即数
		LogD("UDF:" << (code & 0xffff));
		return 0;
	}
	else
	{
		return code & 0x61ff0000;
	}
}

// SME Encodings 组
// op1 = 0000 op0 = 1
int Arm64OpDecorder::_smeEncodings(uint32_t code)
{
	int op0 = GetBitMap(code, 29, 1);//(code >> 29) & 0x3;
	int op1 = GetBitMap(code, 10, 14);//(code >> 10) & 0x7fff;
	int op2 = GetBitMap(code, 1, 3);//(code >> 1) & 0xf;
	if (true)
	{

	}
	return op0;
}


// 指令的执行的条件 当指令的执行条件满足时，指令才被执行，否则指令被忽略
inline bool Arm64OpDecorder::_cond(int cond)
{
	int c = GetBitMap(cond,1,2);
	bool invert = GetBitBool(cond, 0);
	bool ret = true;
	switch (c)
	{
	case 0:
		ret = invert ? NE(_pstate) : EQ(_pstate);
		break;
	case 1:
		ret = invert ? CC(_pstate) : CS(_pstate);
		break;
	case 2:
		ret = invert ? PL(_pstate) : MI(_pstate);
		break;
	case 3:
		ret = invert ? VC(_pstate) : VS(_pstate);
		break;
	case 4:
		ret = invert ? LS(_pstate) : HI(_pstate);
		break;
	case 5:
		ret = invert ? LT(_pstate) : GE(_pstate);
		break;
	case 6:
		ret = invert ? LE(_pstate) : GT(_pstate);
		break;
	case 7:
		return true;
	default:
		Abort("COND Err:" << c);
		break;
	}
	return ret;
}

inline uint8_t Arm64OpDecorder::_S1TranslationRegime(uint8_t el)
{
	if (el == EL0) {
		// ELUsingAArch32(EL3) && SCR.NS == '0'
		if (HaveEL(EL3)& ELUsingAArch32(EL3)&& !SCREL3_NS(_system->scrEL3)) {
			return EL3;
		}
		else if (HaveVirtHostExt() && _ELIsInHost(el)) {
			return EL2;
		}
		else return EL1;
	}
	return el;
}


/*
* 如果低于 EL3 的异常级别处于安全状态，则返回 TRUE
* 或者会在异常后返回到该级别。
* 与 IsSecure 的不同之处在于它忽略当前的 EL 或模式
* 在考虑安全状态时。
* 也就是说，如果在 AArch64 EL3 或 AArch32 监控模式下，无论
* 异常返回将传递到“安全”或“非安全”状态。
*/
inline bool Arm64OpDecorder::_IsSecureBelowEL3()
{
	if (HaveEL(EL3)) {
		//SCR_curr[].NS == '0';
		return !SCREL3_NS(_system->scrEL3);
	}
	else if (HaveEL(EL2) && (!HaveSecureEL2Ext() || !HaveAArch64())) {
		return false;
	}
	return HSA_SECURE_ONLY;
}

inline bool Arm64OpDecorder::_ELStateUsingAArch32(uint8_t el, bool secure)
{
	if (!HaveAArch32EL(el)) return false;// Exception level is using AArch64
	else if (secure && el == EL2) return false;// Secure EL2 is using AArch64
	else if (!HaveAArch64()) return true; //// Highest Exception level, therefore all levels are using AArch32

	bool aarch32 = false;
	bool aarch32_below_el3 = HaveEL(EL3) && (!secure || !HaveSecureEL2Ext() || !SCREL3_EEL2(_system->scrEL3)) && !SCREL3_RW(_system->scrEL3);
	bool aarch32_at_el1 = aarch32_below_el3 || (HaveEL(EL2) && (!secure || (HaveSecureEL2Ext() && SCREL3_EEL2(_system->scrEL3))) && !(HaveVirtHostExt() && HCREL2_E2H(_system->scrEL3) && HCREL2_TGE(_system->scrEL3)) && !HCREL2_RW(_system->scrEL3));
	
	if (el == EL0 && !aarch32_at_el1) {
		if (EL(_pstate) == EL0) {
			aarch32 = _pstate->rw;
		}
	}
	else {
		aarch32 = (aarch32_below_el3 && el != EL3) || (aarch32_at_el1 && el < 2);
	}
	return aarch32;
}

inline bool Arm64OpDecorder::_ELIsInHost(uint8_t el)
{
	if (!HaveVirtHostExt() || ELUsingAArch32(EL2)) return false;
	TODO("");
	if (el == EL3 || el == EL1) return false;
	else if (el == EL0) {
		return	HCREL2_E2H(_system->scrEL3) && HCREL2_TGE(_system->scrEL3) && EL2Enabled(_system->scrEL3);
	}else if (el == EL2) {
		return HCREL2_E2H(_system->scrEL3) && EL2Enabled(_system->scrEL3);
	}
	return false;
}

inline void Arm64OpDecorder::_BranchTo(uint64_t target, BranchType type, bool branch_conditional)
{
	Hint_Branch(type);
	if (!UsingAArch32(_pstate)) {
		target = _AArch64BranchAddr(target, _pstate->el);
		if (HaveBRBExt() && type == BranchType::BranchType_DIR) {
			TODO("");
		}
		if (HaveStatisticalProfiling()) {
			TODO("");
		}	
	}
	_pc = target;
}

inline uint64_t Arm64OpDecorder::_AArch64BranchAddr(uint64_t target, uint8_t el)
{
	uint8_t msbit = _AddrTop(target, true, el);
	if (msbit == 63)	return target;
	TODO("");
	if ((el < EL2 || IsInHost(_pstate->el)) && GetBitBool(target, msbit)) {
		//uint64_t _target;
		//SignExtend(_target, target, msbit);
	}
	return target;
}

inline uint8_t Arm64OpDecorder::_AddrTop(uint64_t target, bool isInstr, uint8_t el)
{
	assert(HaveEL(el));
	uint8_t ret = _S1TranslationRegime(el);

	if (ELUsingAArch32(ret)) {
		return 31;
	}
	else {
		//EffectiveTBI(address, IsInstr, el) == '1'
		if (_effectiveTBI(target, isInstr, el)) {
			return 55;
		}
	}
	return 63;
}

inline bool Arm64OpDecorder::_effectiveTBI(uint64_t target, bool isInstr, uint8_t el)
{
	assert(HaveEL(el));
	uint8_t ret = _S1TranslationRegime(el);
	assert(!ELUsingAArch32(ret));
	bool tbi = false, tbid = false;
	switch (ret)
	{
	case EL1:
		tbi = GetBitBool(target, 55) ? TCR_ELN_TBI1(_system->tcr_el1) : TCR_ELN_TBI0(_system->tcr_el1);
		if (HavePACExt())
			tbid = GetBitBool(target, 55) ? TCR_ELN_TBID1(_system->tcr_el1) : TCR_ELN_TBID0(_system->tcr_el1);
		break;
	case EL2:
		if (HaveVirtHostExt() && _ELIsInHost(el)) {
			tbi = GetBitBool(target, 55) ? TCR_ELN_TBI1(_system->tcr_el2) : TCR_ELN_TBI0(_system->tcr_el2);
			if (HavePACExt())
				tbid = GetBitBool(target, 55) ? TCR_ELN_TBID1(_system->tcr_el2) : TCR_ELN_TBID0(_system->tcr_el2);
		}
		else {
			//tbi == tbi0?
			tbi = TCR_ELN_TBID0(_system->tcr_el2);
			if (HavePACExt())
				tbid = TCR_ELN_TBID0(_system->tcr_el2);
		}
		break;
	case EL3:
		tbi = TCR_ELN_TBID0(_system->tcr_el3);
		if (HavePACExt())
			tbid = TCR_ELN_TBID0(_system->tcr_el3);
		break;
	default:
		break;
	}
	return tbi && (!HavePACExt() || !tbid || !isInstr) ? true : false;
}

inline bool Arm64OpDecorder::_gCSEnabled(uint8_t el)
{
	if (UsingAArch32(_pstate)) return false;

	if (HaveEL(EL3) && el != EL3) {
		LogW(" SCR_EL3.GCSEn == '0' not find");
		return false;
	}
	if (el < EL2 && EL2Enabled(_system->scrEL3) && (HCREL2_TGE(_system->hcr_el2) || HCREL2_E2H(_system->hcr_el2)) &&
		(!_isHCRXEL2Enabled()  )) {
		LogW("  HCRX_EL2.GCSEn == '0' not find");
		return false;
	}
	return false;
}

inline bool Arm64OpDecorder::_isHCRXEL2Enabled()
{
	if (!HaveFeatHCX()) return false;
	if (HaveEL(EL3) && !SCREL3_HXEN(_system->scrEL3)) return false;
	return EL2Enabled(_system->scrEL3);
}

inline uint64_t Arm64OpDecorder::_decodeBitMasks(bool n, BitVar6 imms, BitVar6 immr, bool immD, int width)
{

	BitVar6 levels;

	// Compute log2 of element size
	// 2^len must be in range [2, M]
	// HighestSetBit(immN:NOT(imms));
	int len = _highestSetBit(n ? ((1 << 6) & ~imms.a) : ~imms.a, 7);
	assert(len >= 1);
	assert(width >= (1 << len));
	//// Determine s, r and s - r parameters
	levels.a = ((uint64_t)1 << (len + 1)) - 1;

	assert(!(immD && ((imms.a & levels.a) == levels.a)));

	BitVar6 s = {
		.a = imms.a & levels.a 
	};
	BitVar6 r = {
		.a = immr.a & levels.a
	};

	BitVar6 diff = {
		.a = s.a - r.a
	};
	
	int esize = 1 << len;
	uint64_t d = GetBitMap(diff.a, 0, len);
	uint64_t tmask = 0, wmask = 0;
	uint64_t welem = ((uint64_t)1 << (s.a + 1)) - 1;
	uint64_t telem = ((uint64_t)1 << (d + 1)) - 1;
	int w = width / esize;
	welem = _ror(welem, r.a, esize);
	for (size_t i = 0; i < w; i++)
	{
		tmask = (tmask << (i * esize)) | telem;
		wmask = (wmask << (i * esize)) | welem;
	}
	LogZ("n:" << std::dec << n << std::hex << ",imms:" << imms.a << ",immr:" << immr.a << ",immD:" << immD << ",width:" << width);
	LogZ("len:" << std::dec << len << std::hex << ",s:" << s.a << ",r:" << r.a << ",diff:" << diff.a);
	LogZ("esize:" << std::dec << esize << std::hex << ",d:" << d << ",welem:" << welem << ",telem:" << telem);
	LogZ("tmask:" << std::hex << tmask << ",wmask:" << wmask);

	return wmask;
}

inline int Arm64OpDecorder::_highestSetBit(uint64_t v, int width)
{
	for (int i = width - 1; i >= 0; i--) {
		if (GetBitBool(v, i)) return i;
	}
	return -1;
}

inline uint64_t Arm64OpDecorder::_ror(uint64_t v, int r, int w)
{
	assert(r >= 0);
	uint64_t ret = 0;
	if (r == 0) return v;
	else 
	return _rorC(v,r,w);
}

inline uint64_t Arm64OpDecorder::_rorC(uint64_t v, int r, int w)
{
	assert((r != 0) && (r < 256));
	int m = r % w;
	//result = LSR(x, m) OR LSL(x, N - m);
	return _lsr(v, m) | _lsl(v, w - m, w);
}

inline uint64_t Arm64OpDecorder::_lsr(uint64_t v, int r)
{
	assert(r >= 0);
	return r ? _lsrC(v, r) : v;
}

inline uint64_t Arm64OpDecorder::_lsrC(uint64_t v, int r)
{
	assert((r > 0) && (r < 256));
	//extended_x = ZeroExtend(v, r+w);
	return v >> r;
}

inline uint64_t Arm64OpDecorder::_lsl(uint64_t v, int r, int w)
{
	assert(r >= 0);
	return r ? _lslC(v, r,w) : v;
}

inline uint64_t Arm64OpDecorder::_lslC(uint64_t v, int r,int w)
{
	assert((r > 0) && (r < 256));
	return GetBitMap((v<<r),0,w-1);
}

inline AccessDescriptor Arm64OpDecorder::_createAccDescGPR(MemOp memop, bool nontemporal, bool privileged, bool tagchecked)
{
	SecurityState _ss = _SecurityStateAtEL(EL(_pstate));
	MPAMinfo _mpam = _NewMPAMinfo(AccessType::AccessType_GPR, EL(_pstate));
	AccessDescriptor accdesc = _NewAccDesc(AccessType::AccessType_GPR, EL(_pstate), _ss, _mpam);

	accdesc.el = !privileged ? EL0 : EL(_pstate);
	accdesc.nontemporal = nontemporal;
	accdesc.read = memop == MemOp::MemOp_LOAD;
	accdesc.write = memop == MemOp::MemOp_STORE;
	accdesc.pan = true;
	accdesc.tagchecked = tagchecked;
	accdesc.transactional = HaveTME() && _tstate->depth > 0;
	return accdesc;
}

inline bool Arm64OpDecorder::_aarch64UnalignedAccessFaults(AccessDescriptor* accdesc, uint64_t addr, int size)
{
	if (_AlignmentEnforced()) return true;
	else if ((accdesc->acctype == AccessType::AccessType_GCS) || accdesc->rcw || accdesc->ls64)return true;
	else if (accdesc->exclusive || accdesc->atomicop) {
		//|| !AllInAlignedQuantity(address, size, 16)))
		WARNTODO("because HasLSE2 ia false");
		return  !HaveLSE2Ext();
	}
	else if (accdesc->acqsc || accdesc->acqpc || accdesc->relsc) {
		//||(SCTLR_ELx[].nAA == '0' && !AllInAlignedQuantity(address, size, 16)))
		WARNTODO("because HasLSE2 ia false");
		return  !HaveLSE2Ext();
	}
	return false;
}

inline bool Arm64OpDecorder::_AlignmentEnforced()
{
	Regime regime = _TranslationRegime(EL(_pstate));

	switch (regime)
	{
	case Regime::Regime_EL10:

		return ELUsingAArch32(EL1) ? _system->sctlr_el0.A : _system->sctlr_el1.A;
	case Regime::Regime_EL3:
		break;
	case Regime::Regime_EL30:
		break;
	case Regime::Regime_EL2:
		break;
	case Regime::Regime_EL20:
		break;
	
	}
	WARNTODO("now alawys return false");
	return false;
}

inline Regime Arm64OpDecorder::_TranslationRegime(int el)
{
	if (el == EL3) {
		return ELUsingAArch32(EL3) ? Regime::Regime_EL30 : Regime::Regime_EL3;
	}
	else if (el == EL2) {
		return _ELIsInHost(EL2) ? Regime::Regime_EL20 : Regime::Regime_EL2;
	}
	else if (EL1) {
		return Regime::Regime_EL10;
	}
	else {
		if ((CurrentSecurityState(EL0) == SecurityState::SS_Secure) && ELUsingAArch32(EL3)) {
			return Regime::Regime_EL30;
		}
		else if (_ELIsInHost(EL0)) {
			return Regime::Regime_EL20;
		}
		else {
			return Regime::Regime_EL10;
		}
	}
}

inline SecurityState Arm64OpDecorder::_SecurityStateAtEL(int el)
{
	if (HaveRME()) {
		TODO("RME");
	}

	if (!HaveEL(EL3)) {

		return SecureOnlyImplementation ? SecurityState::SS_Secure : SecurityState::SS_NonSecure;
	}
	else if (el == EL3) {
		return SecurityState::SS_Secure;
	}
	else {
		assert(((el != EL2) || EL2Enabled(_system->scrEL3)));
		return SCREL3_NS(_system->scrEL3) ? SecurityState::SS_NonSecure : SecurityState::SS_Secure;
		//if (!ELUsingAArch32(EL3)) {
		//	return SCREL3_NS(_system->scrEL3) ? SecurityState::SS_NonSecure : SecurityState::SS_Secure;
		//}
		//else {
		//	return SCREL3_NS(_system->scrEL3) ? SecurityState::SS_NonSecure : SecurityState::SS_Secure;
		//}
	}
}

inline MPAMinfo Arm64OpDecorder::_NewMPAMinfo(AccessType acctype, int el)
{
	uint8_t mpamEL = 0;
	SecurityState security = _SecurityStateAtEL(el);
	bool vaildEL = false, inD = false, inSM = false;
	PARTIDspaceType pspace = _PARTIDspaceFromSS(security);

	if ((pspace == PARTIDspaceType::PIdSpace_NonSecure) && !_MPAMisEnabled()) {
		return _DefaultMPAMinfo(pspace);
	}
	if (UsingAArch32(_pstate)) {
		vaildEL = _ELFromM32(_pstate->m,&mpamEL);
	}
	else {
		mpamEL = acctype == AccessType::AccessType_NV2 ? EL2 : el;
		vaildEL = true;
	}

	switch (acctype)
	{
	case AccessType::AccessType_IFETCH:
	case AccessType::AccessType_IC:
		inD = true;
		break;
	case AccessType::AccessType_SVE:
	case AccessType::AccessType_ASIMD:
		inSM = (HaveSME() && _pstate->sm && (SharedSMCUImplementation || MPAMSM_EL1_Label_Implementation));
		break;
	case AccessType::AccessType_SME:
		inSM = SharedSMCUImplementation || MPAMSM_EL1_Label_Implementation;
		break;
	default:
		inD = false;
		break;
	}
	if (!vaildEL) {
		return _DefaultMPAMinfo(pspace);
	}
	else if (HaveSME()) {
		TODO("HaveSME");
	}

	if (HaveMPAMv0p1Ext()) {
		TODO("HaveMPAMv0p1Ext");
	}
	if ((HaveMPAMv0p1Ext() || HaveMPAMv1p1Ext())) {
		TODO("HaveMPAMv1p1Ext");
	}

	if (!_MPAMisEnabled()) {
		return _DefaultMPAMinfo(pspace);
	}
	TODO("MPAMinfo");
	return MPAMinfo();
}

inline MPAMinfo Arm64OpDecorder::_DefaultMPAMinfo(PARTIDspaceType partidspace)
{
	MPAMinfo defaultInfo;
	defaultInfo.mpam_sp = partidspace;
	defaultInfo.partid = 0;
	defaultInfo.pmg = 0;
	return defaultInfo;
}

inline PARTIDspaceType Arm64OpDecorder::_PARTIDspaceFromSS(SecurityState security)
{
	switch (security)
	{
	case SecurityState::SS_NonSecure:
		return PARTIDspaceType::PIdSpace_NonSecure;
	case SecurityState::SS_Root:
		return PARTIDspaceType::PIdSpace_Root;
	case SecurityState::SS_Realm:
		return PARTIDspaceType::PIdSpace_Realm;
	case SecurityState::SS_Secure:
		return PARTIDspaceType::PIdSpace_Secure;
	default:
		UNREACHABLED();
	}
}

inline bool Arm64OpDecorder::_MPAMisEnabled()
{
	switch (_HighestEL())
	{
	case EL3:
		break;
	case EL2:
		break;
	case EL1:
		break;
	default:
		break;
	}
	WARNTODO("now alawys return false");
	return false;
	//UNREACHABLED();
}

inline int Arm64OpDecorder::_HighestEL()
{
	if (HaveEL(EL3)) return EL3;
	else if(HaveEL(EL2)) return EL2;
	return EL1;
}

inline bool Arm64OpDecorder::_ELFromM32(uint64_t mode, uint8_t* el)
{
	bool valid = !_BadMode(mode);

	switch (mode)
	{
	case (uint64_t)M32Mode::M32_Monitor:
		*el = EL3;
		break;
	case (uint64_t)M32Mode::M32_Hyp:
		*el = EL2;
		break;
	case (uint64_t)M32Mode::M32_User:
		*el = EL0;
		break;
	case (uint64_t)M32Mode::M32_FIQ:
	case (uint64_t)M32Mode::M32_IRQ:
	case (uint64_t)M32Mode::M32_Svc:
	case (uint64_t)M32Mode::M32_Abort:
	case (uint64_t)M32Mode::M32_Undef:
	case (uint64_t)M32Mode::M32_System:
		*el = (HaveEL(EL3) && !HaveAArch64() && !SCREL3_NS(_system->scrEL3)) ? EL3 : EL1;
		break;
	default:
		valid = false;
		break;
	}

	if (valid && (*el == EL2) && HaveEL(EL3) && !SCREL3_NS(_system->scrEL3)) {
		valid = false;
	}
	else if (valid && HaveRME()&& _EffectiveSCR_EL3_NSE()&&_EffectiveSCR_EL3_NS()) {
		valid = false;
	}
	
	return valid;
}

inline bool Arm64OpDecorder::_BadMode(uint64_t mode)
{
	bool valid = false;
	switch (mode)
	{
	case (uint64_t)M32Mode::M32_Monitor:
		valid = HaveAArch32EL(EL3);
		break;
	case (uint64_t)M32Mode::M32_Hyp:
		valid = HaveAArch32EL(EL2);
		break;
	case (uint64_t)M32Mode::M32_User:
		valid = HaveAArch32EL(EL1);
		break;
	case (uint64_t)M32Mode::M32_FIQ:
	case (uint64_t)M32Mode::M32_IRQ:
	case (uint64_t)M32Mode::M32_Svc:
	case (uint64_t)M32Mode::M32_Abort:
	case (uint64_t)M32Mode::M32_Undef:
	case (uint64_t)M32Mode::M32_System:
		valid = HaveAArch32EL(EL0);
		break;
	}
	return !valid;
}

inline bool Arm64OpDecorder::_EffectiveSCR_EL3_NS()
{
	if (!_HaveSecureState()) return true;
	else if(!HaveEL(EL3))return false;
	return SCREL3_NS(_system->scrEL3);
}

inline bool Arm64OpDecorder::_EffectiveSCR_EL3_NSE()
{
	return !HaveRME() ? 0 : SCREL3_NSE(_system->scrEL3);
}

inline bool Arm64OpDecorder::_HaveSecureState()
{
	if (!HaveEL(EL3)) return SecureOnlyImplementation;
	else if (HaveRME() && !HaveSecureEL2Ext())
		return false;
	return true;
}

inline bool Arm64OpDecorder::_BigEndian(AccessType acctype)
{
	if (HaveNV2Ext() && acctype == AccessType::AccessType_NV2) {
		return  _system->sctlr_el2.EE;
	}
	if (UsingAArch32(_pstate)) return _pstate->e != 0;
	else if (EL(_pstate) == EL0) return _system->sctlr_el0.EOE != 0;
	TODO("");
	return _system->sctlr_el0.EOE != 0;
}

inline uint64_t Arm64OpDecorder::_BigEndianReverse(uint64_t v, int w)
{
	TODO("_BigEndianReverse");
	return uint64_t();
}

inline FaultRecord Arm64OpDecorder::_NoFault(AccessDescriptor* accdesc)
{
	FaultRecord fault;
	fault.statuscode = Fault::Fault_None;
	fault.accessdesc = *accdesc;
	fault.secondstage = false;
	fault.s2fs1walk = false;
	fault.dirtybit = false;
	fault.overlay = false;
	fault.toplevel = false;
	fault.assuredonly = false;
	fault.s1tagnotdata = false;
	fault.tagaccess = false;
	fault.write = !accdesc->read && accdesc->write;
	fault.gpcfs2walk = false;
	fault.gpcf = _GPCNoFault();
	return fault;
}

inline GPCFRecord Arm64OpDecorder::_GPCNoFault()
{
	GPCFRecord result;
	result.gpf = GPCF::GPCF_None;
	return result;
}

inline bool Arm64OpDecorder::_AArch64S1Enabled(Regime regime, AccessType acctype)
{
	switch (regime)
	{
	case Regime::Regime_EL3:
		return SCTLR_EL_M(_system->sctlr_el3);
	case Regime::Regime_EL2:
	case Regime::Regime_EL20:
		return SCTLR_EL_M(_system->sctlr_el2);
	case Regime::Regime_EL10:
		return (!EL2Enabled(_system->scrEL3) || (!HCREL2_DC(_system->hcr_el2) && !HCREL2_TGE(_system->hcr_el2))) && SCTLR_EL_M(_system->sctlr_el2);
	default:
		break;
	}
	UNREACHABLED();
}

inline AccessDescriptor Arm64OpDecorder::_NewAccDesc(AccessType _acctype, int el, SecurityState _ss, MPAMinfo _mpam)
{

	AccessDescriptor accdesc;
	accdesc.acctype = _acctype;
	accdesc.el = el;
	accdesc.ss = _ss;//SecurityStateAtEL(PSTATE.EL);
	accdesc.acqsc = false;
	accdesc.acqpc = false;
	accdesc.relsc = false;
	accdesc.limitedordered = false;
	accdesc.exclusive = false;
	accdesc.rcw = false;
	accdesc.rcws = false;
	accdesc.atomicop = false;
	accdesc.nontemporal = false;
	accdesc.read = false;
	accdesc.write = false;
	accdesc.pan = false;
	accdesc.nonfault = false;
	accdesc.firstfault = false;
	accdesc.first = false;
	accdesc.contiguous = false;
	accdesc.streamingsve = false;
	accdesc.ls64 = false;
	accdesc.mops = false;
	accdesc.a32lsmd = false;
	accdesc.tagchecked = false;
	accdesc.tagaccess = false;
	accdesc.transactional = false;
	accdesc.mpam = _mpam;// GenMPAMcurEL(_acctype);
	accdesc.ispair = false;
	accdesc.highestaddressfirst = false;
	return accdesc;

}

inline bool Arm64OpDecorder::_AArch64S1POEnabled(Regime regime)
{
	if (!HaveS1POE())	return false;
	TODO("");
	return false;
}

inline bool Arm64OpDecorder::_AArch64S1E0POEnabled(Regime regime, bool nv1)
{
	assert(HasUnprivileged(regime));
	if (!HaveS1POE())	return false;
	TODO("");
	return false;
}

inline TGx Arm64OpDecorder::_AArch64S1DecodeTG0(int tg0)
{
	assert(tg0 >= 0 && tg0 < 4);
	TGx tgx = TGx::TGx_4KB;
	if (tg0 == 3) {
		TODO("");
	}
	switch (tg0)
	{
	case 0:
		tgx = TGx::TGx_4KB;
		break;
	case 1:
		tgx = TGx::TGx_64KB;
		break;
	case 2:
		tgx = TGx::TGx_16KB;
		break;
	}
	if (!AArch64HaveS1TG(tgx)) {
		TODO("");
	}
	return tgx;
}

#include "LoadAndStores.cpp"
#include "GeneralSys.cpp"
#include "DataProcessing.cpp"
